package com.jielihaofeng.netty.helloworld;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.logging.LoggingHandler;

/**
 * @author Johnnie Wind
 * @description Hello World 服务端
 * @date 2021/11/8 17:36
 */
public class HelloServer {

    public static void main(String[] args) throws InterruptedException {
        // 1. 启动器，负责组装 netty 组件，启动服务器
        new ServerBootstrap()
                // 2. BossEventLoop, WorkerEventLoop(selector,thread), group 组
                .group(new NioEventLoopGroup())
                // 3. 选择 服务器的 ServerSocketChannel 实现
                .channel(NioServerSocketChannel.class)
                // 4. boss 负责处理连接 worker(child) 负责处理读写，决定了 worker(child) 能执行哪些操作（handler）
                .childHandler(
                        // 5. channel 代表和客户端进行数据读写的通道 Initializer 初始化，负责添加别的 handler
                        new ChannelInitializer<NioSocketChannel>() {
                            @Override
                            protected void initChannel(NioSocketChannel ch) {
                                // 6. 添加具体 handler
                                // 7. 日志 handler
                                ch.pipeline().addLast(new LoggingHandler());
                                // 将 ByteBuf 转换为字符串
                                ch.pipeline().addLast(new StringDecoder());
                                // 自定义 handler
                                ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
                                    // 读事件
                                    @Override
                                    public void channelRead(ChannelHandlerContext ctx, Object msg) {
                                        // 打印上一步转换好的字符串
                                        System.out.println("客户端" + ch.remoteAddress().getPort() + "：" + msg);
                                    }
                                });
                            }
                        })
                .handler(new ChannelInitializer<NioServerSocketChannel>() {
                    @Override
                    protected void initChannel(NioServerSocketChannel nioServerSocketChannel) throws Exception {
                        System.out.println("服务器已启动");
                    }
                })
                .bind(8088);
    }

}

// 一开始需要树立正确的观念
//
//* 把 channel 理解为数据的通道
//* 把 msg 理解为在channel中流动的数据，最开始输入是 ByteBuf，但经过 pipeline 的加工，会变成其它类型对象，最后输出又变成 ByteBuf
//* 把 handler 理解为数据的处理工序
//  * 工序有多道，合在一起就是 pipeline（流水线），pipeline 负责发布事件（读、读取完成...）传播给每个 handler， handler 对自己感兴趣的事件进行处理（重写了相应事件处理方法）
//  * handler 分 Inbound（入栈：写入数据时） 和 Outbound（出栈：写出数据时） 两类
//* 把 eventLoop 理解为处理数据的工人
//  * 工人可以管理多个 channel 的 io 操作，并且一旦工人负责了某个 channel，就要负责到底（绑定）
//  * 工人既可以执行 io 操作，也可以进行任务处理，每位工人有任务队列，队列里可以堆放多个 channel 的待处理任务，任务分为普通任务、定时任务
//  * 工人按照 pipeline 顺序，依次按照 handler 的规划（代码）处理数据，可以为每道工序指定不同的工人（出入时要绑定，但是中间做一些操作可以指定不同的工人）